package com.qclix.inv.dao;

import com.qclix.inv.Invoice;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.sql.SQLException;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * InvoiceDAO implementation relying on hibernate
 */
public class HibernateTemplateInvoiceDaoImpl extends HibernateDaoSupport implements InvoiceDAO {
    @Transactional(propagation = Propagation.REQUIRED)
    public void add(Invoice invoice) throws DAOException {
        getHibernateTemplate().save(invoice);
    }

    private static final String AMOUNT_OF_INVOICES_SINCE_DATE =
            "select count(invoice.id) from Invoice invoice where invoice.issueDate >= :date and invoice.issueDate < :dateNextYear";
    public long getAmountOfInvoicesOnYear(int year) throws DAOException {
        Calendar cal = Calendar.getInstance();
        cal.set(year,0,0);
        final Date firstDayOfYear = cal.getTime();
        cal.set(Calendar.YEAR, year);
        final Date firstDayOfNextYear = cal.getTime();
        return (Long) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query query = getSession().createQuery(AMOUNT_OF_INVOICES_SINCE_DATE);
                query.setParameter("date", firstDayOfYear);
                query.setParameter("dateNextYear", firstDayOfNextYear);
                return query.uniqueResult();
            }
        });
    }

    private static final String LAST_INVOICE_QUERY =
            "select invoice from Invoice invoice where invoice.issueDate = (select max(inv.issueDate) from Invoice inv) ";
    @SuppressWarnings("unchecked")
    public Invoice getLastInvoice() throws DAOException {
        return (Invoice) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query query = getSession().createQuery(LAST_INVOICE_QUERY);
                List<Invoice> sameDayInvoices = query.list();
                if (sameDayInvoices.size() == 1) {
                    return sameDayInvoices.get(0);
                }
                Collections.sort(sameDayInvoices);
                return sameDayInvoices.get(sameDayInvoices.size() - 1);
            }
        });
    }

    private static final String LAST_INVOICES_QUERY =
            "select invoice from Invoice invoice order by invoice.issueDate DESC";
    @SuppressWarnings("unchecked")
    public List<Invoice> getLastInvoices(final int amount) throws DAOException {
        if (amount <= 0) {
            throw new IllegalArgumentException("The amount of data to return must be a positive integer");
        }
        return (List<Invoice>) getHibernateTemplate().execute(new HibernateCallback() {
            public Object doInHibernate(Session session) throws HibernateException, SQLException {
                Query query = getSession().createQuery(LAST_INVOICES_QUERY);
                query.setMaxResults(amount);
                return query.list();
            }
        });
    }
}
